package me.seawenc.db.migration.service.translator.mysql;

import java.util.stream.Collectors;
import me.seawenc.db.migration.bean.TableBean;
import me.seawenc.db.migration.bean.table.TableFieldBean;
import me.seawenc.db.migration.dbengine.FieldType;
import me.seawenc.db.migration.helper.Optionalx;
import me.seawenc.db.migration.service.translator.BaseTranslator;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static me.seawenc.db.migration.dbengine.FieldType.*;

public class MysqlTranslator implements BaseTranslator {
    private final Map<FieldType, List<String>> MAPPING = new HashMap<>();

    public MysqlTranslator() {
        MAPPING.put(BIT, list("BIT"));
        MAPPING.put(TINYINT, list("TINYINT"));
        MAPPING.put(BOOLEAN, list("BOOLEAN"));
        MAPPING.put(SMALLINT, list("SMALLINT"));
        MAPPING.put(MEDIUMINT, list("MEDIUMINT"));
        MAPPING.put(INTEGER, list("INT", "INTEGER"));
        MAPPING.put(BIGINT, list("BIGINT"));
        MAPPING.put(DECIMAL, list("DECIMAL"));
        MAPPING.put(NUMERIC, list("NUMERIC"));
        MAPPING.put(FLOAT, list("FLOAT"));
        MAPPING.put(REAL, list("REAL"));
        MAPPING.put(DOUBLE, list("DOUBLE"));
        MAPPING.put(CHAR, list("CHAR"));
        MAPPING.put(VARCHAR, list("VARCHAR"));
        MAPPING.put(BINARY, list("BINARY"));
        MAPPING.put(VARBINARY, list("VARBINARY"));
        MAPPING.put(TINYBLOB, list("TINYBLOB"));
        MAPPING.put(BLOB, list("BLOB"));
        MAPPING.put(MEDIUMBLOB, list("MEDIUMBLOB"));
        MAPPING.put(LONGBLOB, list("LONGBLOB"));
        MAPPING.put(TINYTEXT, list("TINYTEXT"));
        MAPPING.put(TEXT, list("TEXT"));
        MAPPING.put(MEDIUMTEXT, list("MEDIUMTEXT"));
        MAPPING.put(LONGTEXT, list("LONGTEXT"));
        MAPPING.put(ENUM, list("ENUM"));
        MAPPING.put(SET, list("SET"));
        MAPPING.put(JSON, list("JSON"));
        MAPPING.put(DATE, list("DATE"));
        MAPPING.put(DATETIME, list("DATETIME"));
        MAPPING.put(TIMESTAMP, list("TIMESTAMP"));
        MAPPING.put(TIME, list("TIME"));
        MAPPING.put(YEAR, list("YEAR"));
        MAPPING.put(GEOMETRY, list("GEOMETRY"));
        MAPPING.put(LINESTRING, list("LINESTRING"));
        MAPPING.put(POLYGON, list("POLYGON"));
        MAPPING.put(POINT, list("POINT"));
        MAPPING.put(GEOMETRYCOLLECTION, list("GEOMETRYCOLLECTION"));
        MAPPING.put(MULTILINESTRING, list("MULTILINESTRING"));
        MAPPING.put(MULTIPOLYGON, list("MULTIPOLYGON"));
        MAPPING.put(MULTIPOINT, list("MULTIPOINT"));
    }

    @Override
    public void filedType2Logic(TableFieldBean tableFieldBean) {
        FieldType logicType = MAPPING.entrySet().stream()
                .filter(entry -> entry.getValue().contains(tableFieldBean.getSrcType().toUpperCase()))
                .findAny()
                .orElseThrow(() -> new RuntimeException("未知的字段类型：" + tableFieldBean.getSrcType()))
                .getKey();
        tableFieldBean.setLogicType(logicType);
    }

    @Override
    public void filedType2Physical(TableFieldBean tableFieldBean) {
        // 因为逻辑模型以mysql为基础，因此不需要转换
        return ;
    }

    @Override
    public String buildCreateTableSql(TableBean table) {
        // 生成基本结构
        StringBuilder sql = new StringBuilder(String.format("create table %s (",table.getTableName()));
        for (int i = 0; i < table.getFields().size(); i++) {
            TableFieldBean field = table.getFields().get(i);
            String type= Optionalx.isPresent(field.getLength())?String.format("%s(%s)",field.getSrcType(),field.getLength()):field.getSrcType();
            String allowNull = "N".equals(field.getAllowNull()) ? "" : "not null";
            String defaultVal = Optionalx.isPresent(field.getDefaultValue())?String.format("default %s",field.getDefaultValue()):"";
            String splitChar = i == table.getFields().size() - 1 ? "" : ",";
            sql.append(String.format("%s %s %s %s %s\n",field.getName(),type, allowNull,defaultVal, splitChar));
        }
        sql.append(");\n\n");

        // 设置主键
        String idFields = table.getFields().stream().filter(f -> f.getPriKey() != null).map(f -> f.getName()).collect(Collectors.joining(","));
        if(Optionalx.isPresent(idFields)){
            sql.append(String.format("alter table %s add primary key (%s);\n\n",table.getTableName(),idFields));
        }

        // 生成注释
        for (TableFieldBean field: table.getFields()) {
            sql.append(String.format("comment on column %s.%s is '%s';\n",table.getTableName(),field.getName(),field.getComment()));
        }

        return sql.toString();
    }
}
